package com.yld.demo2.controller;


import cn.hutool.core.util.BooleanUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.yld.demo2.entity.table.OrderList;
import com.yld.demo2.entity.vo.OrderListVo;
import com.yld.demo2.service.OrderListService;
import com.yld.demo2.util.DataUtil;
import com.yld.demo2.util.RedisConstants;
import com.yld.demo2.util.tooltips.ResBean;
import io.swagger.annotations.ApiOperation;
import jdk.nashorn.internal.ir.CallNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@RestController
public class OrderListRedisController {

    //关联数据
    List<String> userIdList = new ArrayList<>();

    @Autowired
    OrderListService orderListService;

    @Autowired
    RedisTemplate redisTemplate;

    //缓存击穿
    @GetMapping("/selectRedisAllByUserId2/{user_id}")
    @ApiOperation("根据用户编号user_id查询")
    public ResBean selectByUserId2(@PathVariable("user_id") Integer userid) {

        String key = RedisConstants.ORDER_LIST_KEY + userid;
        //1.判断redis缓存有无值？
        //redis缓存中有值
        if (redisTemplate.opsForList().getOperations().hasKey("userId="+userid)) {
            List range = redisTemplate.opsForList().range("userId="+userid, 0, -1);
            for (Object o : range) {
                System.out.println(o.toString());
            }
            System.out.println("这是从redis中获取值！！！！！！！");
            return ResBean.success(range);
        } else {
            //redis中没有值 查询数据库
            //加锁
            System.out.println("进入数据库中查询！！！！！！！！！！！！！！！！！！！！！！！");
            boolean isLock = tryLock(userid.toString());
            if (isLock) {
                //加锁成功 查询数据库
                List<OrderListVo> orderListVo = orderListService.selectAllByUserId(userid);
                if (orderListVo != null && orderListVo.size() > 0) {
                    redisTemplate.opsForList().leftPushAll("userId="+userid, orderListVo,RedisConstants.ORDER_LIST_TTL,TimeUnit.MINUTES);
                    redisTemplate.expire("userId="+userid,RedisConstants.ORDER_LIST_TTL,TimeUnit.MINUTES);
//                    redisTemplate.opsForValue().set("userId="+userid, orderListVo,RedisConstants.ORDER_LIST_TTL,TimeUnit.MINUTES);

                } else {

                    JSONObject jsonObject = new JSONObject();
                    jsonObject.set("res",null);
                    return ResBean.success(jsonObject);
                }
                //解锁：
                unLock(userid.toString());
                return ResBean.success(orderListVo);
            }else {
                //加锁失败 休眠100ms
                try {
                    Thread.sleep(100);
                    selectByUserId2(userid);

                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

        }


        return ResBean.success();
    }


    //加锁
    private boolean tryLock(String key) {
        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(key, 1, 10000, TimeUnit.SECONDS);
        System.out.println("进入加锁操作");
        return BooleanUtil.isTrue(aBoolean);
    }

    private void unLock(String key) {
        Boolean delete = redisTemplate.delete(key);
        System.out.println("解锁成功+++++++++++++++++++++++++++++++++++++++++++++++++");
        System.out.println(delete);
    }

    @GetMapping("/selectRedisAllByUserId/{user_id}")
    @ApiOperation("根据用户编号user_id查询")
    public ResBean selectByUserId(@PathVariable("user_id") Integer userid) {
        //缓存穿透解决方法2----->设置黑名单
        //(1)先判断这个key是否在黑名单
        Boolean flag = redisTemplate.opsForSet().isMember("NullSet", userid);
        if (flag) {
            // 返回空值
            JSONObject json = new JSONObject();
            json.set("res", null);
            // 返回空值
            return ResBean.success(json);
        }

        Object cache = redisTemplate.opsForValue().get(userid.toString());

        if (cache != null) {
            // 存在缓存
            return ResBean.success(cache);
        } else {
            //不存在缓存的情况下 就要去数据库查询
            List<OrderListVo> orderListVo = orderListService.selectAllByUserId(userid);
            //查询出来有数据 扔入缓存中 没有数据就将key加入黑名单列表
            if (orderListVo != null && orderListVo.size() > 0) {
                redisTemplate.opsForValue().set("userid+"+userid, orderListVo,RedisConstants.ORDER_LIST_TTL,TimeUnit.MINUTES);
                return ResBean.success("查询成功!!!");

            } else {
                //无数据加入黑名单
                redisTemplate.opsForSet().add("NullSet", userid,RedisConstants.CACHE_NULL_TTL,TimeUnit.MINUTES);
                JSONObject jsonObject = new JSONObject();
                jsonObject.set("res", null);
                System.out.println("将key加入黑名单成功!!");
                //返回空值
                return ResBean.success(jsonObject);
            }

        }

        /*//数据校验
        if (userid == null || " ".equals(userid)) {
            return ResBean.FAIL_DML();
        }
        //先查询redis缓存
        else if (redisTemplate.opsForList().getOperations().hasKey("userId=" + userid)) {

            System.out.println("在redis中查询！！！");
            //true 则返回结果
            List range = redisTemplate.opsForList().range("userId=" + userid, 0, -1);
            for (Object o : range) {
                System.out.println(o.toString());
            }
            //验证是否集合为空
            if (range.isEmpty()) {
                return ResBean.noData();
            } else {
                return ResBean.success(range);
            }

        }
        //查询数据库
        else {
            System.out.println("在数据库中查询！！！");
            //通过userid得到全部订单
            List<OrderListVo> orderListVos = orderListService.selectAllByUserId(userid);
            //全部订单写到redis
            if (orderListVos == null) {
                //没有数据 缓存空值或者默认值
                //解决缓存穿透  ---->   redis中没有数据 数据库也没有 当大量请求访问时并发量超级大的时候，给数据库压力巨大 造成数据库宕机
                //1.空值缓存（方案一）--> 在 方案一中 对所有的非法key都做了缓存，而且都是同样的value，这样的操作造成了数据冗余，而且key的数量非常多
                *//*redisTemplate.opsForValue().set("userId="+ userid,null,10,TimeUnit.SECONDS);*//*
                return ResBean.success();
            } else {
                redisTemplate.opsForList().leftPushAll("userId=" + userid, orderListVos,60*5,TimeUnit.SECONDS);
                return ResBean.success(orderListVos);
            }

        }*/

    }

    @GetMapping("/selectRedisAll")
    @ApiOperation("查询全部")
    public ResBean selectAll() {

        List<OrderListVo> orderListVos = orderListService.selectAll();

        System.out.println(orderListVos);

        return ResBean.success(orderListVos);

    }


    @PutMapping("/insertRedisAll")
    @ApiOperation("添加方法 添加所有")
    public ResBean insertAll(@RequestBody OrderListVo orderList) {

        if (orderList.getOrdernum() == 0 | orderList.getAmout() == 0) {
            return ResBean.numberOrMoneyNotZero();
        }
        //获取当前 年月日
        OrderListVo orderListVo = DataUtil.nowDate(orderList);
        //数据库添加
        Boolean aBoolean = orderListService.insertAll(orderListVo);

        //添加到redis
        redisTemplate.opsForList().rightPush("userId=" + orderList.getUserid(), orderListVo);


        return ResBean.success(aBoolean);
    }


    @ApiOperation("根据订单号order_no 删除")
    @DeleteMapping("/deleteRedisByOrderNo/{orderno}")
    public ResBean deleteByOrderNo(@PathVariable Integer orderno) {
        //取到userId
        Integer userid = orderListService.selectUserIdByOrderNo(orderno);

        if (null == userid || " ".equals(userid)) {
            return ResBean.success("没有订单可删除");
        } else {
            //清除redis
            redisTemplate.opsForList().getOperations().delete("userId=" + userid);
            //清除mysql订单
            orderListService.deleteByOrderNo(orderno);

            return ResBean.success("删除成功");
        }
    }


    @ApiOperation("根据订单号order_no 修改")
    @PutMapping("/updateByOrderNoRedis")
    public ResBean updateByOrderNo(@RequestBody OrderListVo orderListVo) {

        // 金额 和 交易数量 不能为0
        if (orderListVo.getOrdernum() == 0 | orderListVo.getAmout() == 0) {
            return ResBean.numberOrMoneyNotZero();
        }
//
//        //判断要修改的 数据 在数据库中 是否存在
//        if (orderListService.selectAllByUserId(orderListVo.getOrderno()) == null){
//            return ResBean.noData();
//        }
//        //订单在redis里面出现的下标
//        List<OrderListVo> range = redisTemplate.opsForList().range("userId=" + orderListVo.getUserid(), 0, -1);
//        int i=0;
//        for (i = 0; i < range.size(); i++) {
//            if(range.get(i).getOrderno().equals(orderListVo.getOrderno())) break;
//        }
//        System.out.println("i===="+i);

        //redis缓存的替换
        redisTemplate.opsForList().getOperations().delete("userId=" + orderListVo.getUserid());


        //数据库的修改操作
        Boolean aBoolean = orderListService.updateByOrderNo(orderListVo);


        return ResBean.success(aBoolean);
    }


}
